package cn.st4rlight.util.enums;

import java.lang.reflect.Method;
import java.util.Objects;

import org.apache.commons.lang3.ArrayUtils;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

/**
 * @author st4rlight <st4rlight@163.com>
 * Created on 2025-05-03
 */
@Slf4j
public class EnumValidator implements ConstraintValidator<EnumValidate, Enum<?>> {

    // 是否允许为空
    private boolean allowNull;
    // 是否允许为0
    private boolean allowZero;
    // 目标枚举类
    private Enum<?>[] enumValues;
    // 目标类是否是 HasCodeAndDesc
    private boolean isHasCodeAndDesc;
    // 获取枚举类中 getValue 方法
    private Method getValueMethod;


    @Override
    @SneakyThrows
    public void initialize(EnumValidate constraintAnnotation) {
        this.allowNull = constraintAnnotation.allowNull();
        this.allowZero = constraintAnnotation.allowZero();
        Class<? extends Enum<?>> targetEnum = constraintAnnotation.target();
        this.enumValues = targetEnum.getEnumConstants();
        this.isHasCodeAndDesc = isEnumImplementInterface(targetEnum, HasCodeAndDesc.class);
        this.getValueMethod = targetEnum.getMethod("getValue");
    }

    @Override
    public boolean isValid(Enum<?> value, ConstraintValidatorContext context) {
        if (ArrayUtils.isEmpty(this.enumValues)) {
            return true;
        }

        try {
            if (Objects.isNull(value)) {
                return this.allowNull;
            }
            if (!this.allowZero && "0".equals(value.toString()))  {
                return false;
            }

            for (Enum<?> enumValue : this.enumValues) {
                Object code = this.isHasCodeAndDesc
                      ? ((HasCodeAndDesc) enumValue).getCode()
                      : this.getValueMethod.invoke(enumValue, null);
                if (value.toString().equals(code.toString())) {
                    return true;
                }
            }
        } catch (Exception ex) {
            log.error("EnumValidator error: {}", ex.getMessage(), ex);
        }

        return false;
    }

    /**
     * 判断枚举类是否实现了某个接口
     */
    private static boolean isEnumImplementInterface(Class<?> enumClass, Class<?> interfaceClass) {
        return enumClass.isEnum() && interfaceClass.isInterface()
                && interfaceClass.isAssignableFrom(enumClass);
    }
}
